package gu.simplemq.pool;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import gu.simplemq.Constant;
import gu.simplemq.exceptions.SmqRuntimeException;

/**
 * 线程安全的消息组件实例管理类
 * @author guyadong
 *
 * @param <R> 消息组件组件类型
 * @param <P> 连接线程池类型
 */
public class  BaseMQInstance<R,P> implements Constant{
	/** 保存每个 P对应的 R 实例 */
	private final LoadingCache<P, R> cache = 
			CacheBuilder.newBuilder()
			.build(new CacheLoader<P,R>(){
				@Override
				public R load(P key) throws Exception {
					constructor.setAccessible(true);
					return constructor.newInstance(key);
				}});
	/** R 的构造方法 */
	private final Constructor<R> constructor;
	/**
	 * usage:<pre>new BaseMQInstance&lt;Model,Pool&gt;(){};</pre>
	 */
	@SuppressWarnings("unchecked")
	protected BaseMQInstance() {
		Type superClass = getClass().getGenericSuperclass();
		Class<R> rClass = (Class<R>) ((ParameterizedType) superClass).getActualTypeArguments()[0];
		Class<P> pClass = (Class<P>) ((ParameterizedType) superClass).getActualTypeArguments()[1];
		constructor = getConstructor(rClass, pClass);
	}
	/**
	 * 构造方法
	 * @param rClass 消息组件类型
	 * @param pClass 连接线程池类型
	 */
	public BaseMQInstance(Class<R> rClass,Class<P> pClass) {
		constructor = getConstructor(rClass, pClass);
	}

	/**
	 * 获取R的构造函数<br>
	 * 首先尝试匹配构造函数参数类型为P的构造函数，如果没有则尝试匹配参数类型为可赋值给P的构造函数。如果都没有则抛出异常。
	 * 
	 * @param rClass 消息组件类型
	 * @param pClass 连接线程池类型
	 * @return R的构造方法
	 */
	@SuppressWarnings("unchecked")
	private Constructor<R> getConstructor(Class<R> rClass, Class<P> pClass) {
		Constructor<R> matched = null;
		try {
			matched = (Constructor<R>) rClass.getDeclaredConstructor(pClass);
		} catch (NoSuchMethodException e) {
			for (Constructor<?> ctor : rClass.getDeclaredConstructors()) {
				Class<?>[] parameterTyeps = ctor.getParameterTypes();
				if (parameterTyeps.length == 1 && parameterTyeps[0].isAssignableFrom(pClass)) {
					matched = (Constructor<R>) ctor;
					break;
				}
			}
			if (matched == null) {
				throw new SmqRuntimeException(e);
			}
		} catch (Throwable e) {
			throw new SmqRuntimeException(e);
		}
		return matched;
	}
	protected void beforeDelete(R r){
		logger.debug("CLOSE MQ instance {}", r);
		/**
		 * AutoCloseable 是 Java 7 引入的接口，Closeable 是 Java 5 引入的接口，
		 * 为兼容性考虑，这里分别判断是否实现了AutoCloseable和Closeable接口，
		 * 并分别执行close方法
		 */
		if(r instanceof AutoCloseable) {
			try {
				((AutoCloseable)r).close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else if(r instanceof Closeable) {
			try {
				((Closeable)r).close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/** 删除{@link #cache}中所有实例,
	 * 如果实例实现了{@link AutoCloseable}接口则执行close方法 */
	public synchronized void  clearInstances(){
			for(R r:cache.asMap().values()){
				beforeDelete(r);
			}
			cache.asMap().clear();
	}
	/**
	 * 返回 {@link #cache}中 P 对应的R实例, 如果没有找到就创建一个新实例加入。
	 * @param pool
	 * @return R instance
	 */
	public R getInstance(P pool){
		return cache.getUnchecked(pool);
	}
}